package com.techsoft.session;

import java.util.Iterator;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.techsoft.Cache;
import com.techsoft.Session;
import com.techsoft.cache.CacheFactory;

public class SessionManager {
	private static String sessinCacheName = "sessions";
	private static SessionManager instance = null;
	private Cache<String, Session> sessions = null;
	private ScheduledExecutorService executor = null;
	private SessionMonitor sessionMonitor;

	private SessionManager() {
		sessions = CacheFactory.getCache(SessionManager.sessinCacheName);
		executor = new ScheduledThreadPoolExecutor(1);
		sessionMonitor = new SessionMonitor();
		executor.scheduleWithFixedDelay(sessionMonitor, 0, 1, TimeUnit.HOURS);
	}

	public static SessionManager getInstance() {
		if (instance == null) {
			instance = new SessionManager();
		}

		return instance;
	}

	public Session getSession(String token) {
		return sessions.get(token);
	}

	public Session CreateLocalSession() {
		return new LocalSession();
	}

	public void setSession(String token, Session session) {
		sessions.put(token, session);
	}

	public void updateSessionLastAccessTime(Session session) {
		session.setLastAccessTime(System.currentTimeMillis());
		sessions.put(session.getAuthToken(), session);
	}

	private class SessionMonitor implements Runnable {
		private boolean running = false;

		@Override
		public void run() {
			synchronized (this) {
				if (running) {
					return;
				}
				running = true;
			}

			try {
				Iterator<String> keys = sessions.keySet().iterator();
				while (keys.hasNext()) {
					String key = keys.next();
					Session session = sessions.get(key);
					Long sessionidletime = session.getLastAccessTime()
							+ Session.IDLETIME * 1000;
					if (System.currentTimeMillis() <= sessionidletime) {
						sessions.remove(key);
					}
				}
			} finally {
				synchronized (this) {
					running = false;
				}
			}

		}
	}
}
